package com.cyneck.demo.utils;

import com.cyneck.demo.model.FaceRequestDto;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.net.ssl.SSLException;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;


@Component
@Slf4j
public class FaceImageClient {


    @Value("${faceplus.ak}")
    private String ak;

    @Value("${faceplus.sk}")
    private String sk;

    private final static int CONNECT_TIME_OUT = 30000;
    private final static int READ_OUT_TIME = 50000;
    private static String boundaryString = getBoundary();

    /**
     * 识别传入图片中人体的完整轮廓，进行人形抠像。
     * 当图像中有多个人时，暂不支持从重叠部分区分出单个人的轮廓。
     *
     * @param return_grayscale 0：不返回灰度图，仅返回人像图片；1：返回灰度图及人像图片；2：只返回灰度图
     * @param imageBuff        图片字节
     * @return
     */
    public Map<String, Object> getSegmentImageByForm(String return_grayscale, byte[] imageBuff) {

        String url = "https://api-cn.faceplusplus.com/humanbodypp/v2/segment";
        HashMap<String, String> map = new HashMap<>();
        HashMap<String, byte[]> byteMap = new HashMap<>();
        map.put("api_key", ak);
        map.put("api_secret", sk);
        map.put("return_grayscale", return_grayscale);
        byteMap.put("image_file", imageBuff);
        Map<String, Object> result = new HashMap<>();
        try {
            byte[] bacd = post(url, map, byteMap);
            String str = new String(bacd);
            Gson gson = new Gson();
            result = gson.fromJson(str, map.getClass());
            log.debug("result:{}", result);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException("业务异常", e);
        }
        return result;
    }

    /**
     * 支持对图片中人像进行对美颜美型处理，以及对图像增加滤镜等。美颜包括：美白和磨皮；美型包括：大眼、瘦脸、小脸等处理。
     * 图片格式：JPG(JPEG)，PNG
     * 图片像素尺寸：最小48*48像素，最大4096*4096像素
     * 图片文件大小：<=2MB
     *
     * @param imageBuff      图片数据
     * @param faceRequestDto 参数
     * @return
     */
    public Map<String, Object> getFace(byte[] imageBuff, FaceRequestDto faceRequestDto) {

        String url = "https://api-cn.faceplusplus.com/facepp/v2/beautify";
        HashMap<String, String> map = new HashMap<>();
        HashMap<String, byte[]> byteMap = new HashMap<>();
        map.put("api_key", ak);
        map.put("api_secret", sk);
        map.put("whitening", faceRequestDto.getWhitening().toString());//美白程度
        map.put("smoothing", faceRequestDto.getSmoothing().toString());//磨皮程度
        map.put("thinface", faceRequestDto.getThinface().toString());//瘦脸程度
        map.put("shrink_face", faceRequestDto.getShrink_face().toString());//小脸程度
        map.put("enlarge_eye", faceRequestDto.getEnlarge_eye().toString());//大眼程度

        byteMap.put("image_file", imageBuff);
        Map<String, Object> result = new HashMap<>();
        try {
            byte[] bacd = post(url, map, byteMap);
            String str = new String(bacd);
            Gson gson = new Gson();
            result = gson.fromJson(str, map.getClass());
            log.debug("result:{}", result);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException("业务异常", e);
        }
        return result;
    }


    public static Map<String, Object> getSegmentImageDev(String imageFile) {
        HashMap<String, Object> map = new HashMap<>();
        map.put("body_image", ImageUtils.getImageBase64Str(imageFile));
        return map;
    }

    protected byte[] post(String url, HashMap<String, String> map, HashMap<String, byte[]> fileMap) throws Exception {
        HttpURLConnection conne;
        URL url1 = new URL(url);
        conne = (HttpURLConnection) url1.openConnection();
        conne.setDoOutput(true);
        conne.setUseCaches(false);
        conne.setRequestMethod("POST");
        conne.setConnectTimeout(CONNECT_TIME_OUT);
        conne.setReadTimeout(READ_OUT_TIME);
        conne.setRequestProperty("accept", "*/*");
        conne.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundaryString);
        conne.setRequestProperty("connection", "Keep-Alive");
        conne.setRequestProperty("user-agent", "Mozilla/4.0 (compatible;MSIE 6.0;Windows NT 5.1;SV1)");
        DataOutputStream obos = new DataOutputStream(conne.getOutputStream());
        Iterator iter = map.entrySet().iterator();
        while (iter.hasNext()) {
            Map.Entry<String, String> entry = (Map.Entry) iter.next();
            String key = entry.getKey();
            String value = entry.getValue();
            obos.writeBytes("--" + boundaryString + "\r\n");
            obos.writeBytes("Content-Disposition: form-data; name=\"" + key
                    + "\"\r\n");
            obos.writeBytes("\r\n");
            obos.writeBytes(value + "\r\n");
        }
        if (fileMap != null && fileMap.size() > 0) {
            Iterator fileIter = fileMap.entrySet().iterator();
            while (fileIter.hasNext()) {
                Map.Entry<String, byte[]> fileEntry = (Map.Entry<String, byte[]>) fileIter.next();
                obos.writeBytes("--" + boundaryString + "\r\n");
                obos.writeBytes("Content-Disposition: form-data; name=\"" + fileEntry.getKey()
                        + "\"; filename=\"" + encode(" ") + "\"\r\n");
                obos.writeBytes("\r\n");
                obos.write(fileEntry.getValue());
                obos.writeBytes("\r\n");
            }
        }
        obos.writeBytes("--" + boundaryString + "--" + "\r\n");
        obos.writeBytes("\r\n");
        obos.flush();
        obos.close();
        InputStream ins = null;
        int code = conne.getResponseCode();
        try {
            if (code == 200) {
                ins = conne.getInputStream();
            } else {
                ins = conne.getErrorStream();
            }
        } catch (SSLException e) {
            e.printStackTrace();
            return new byte[0];
        }
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buff = new byte[4096];
        int len;
        while ((len = ins.read(buff)) != -1) {
            baos.write(buff, 0, len);
        }
        byte[] bytes = baos.toByteArray();
        ins.close();
        return bytes;
    }

    private static String getBoundary() {
        StringBuilder sb = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < 32; ++i) {
            sb.append("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-".charAt(random.nextInt("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_".length())));
        }
        return sb.toString();
    }

    private String encode(String value) throws Exception {
        return URLEncoder.encode(value, "UTF-8");
    }

}
